<?php

namespace App\Trip\Wechat\Account;


// 公众号授权登录
use App\Models\User\Repositories\Interfaces\UserRepositoryInterface;
use App\Models\User\Repositories\Interfaces\WechatOfficialUserRepositoryInterface;
use App\Models\User\User;
use App\Models\User\WechatOfficialUser;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\OfficialAccount\Application;
use EasyWeChat\OfficialAccount\Utils;

class WechatOfficialLogin implements WechatLoginInterface
{
    private Application $official;
    private Utils       $utils;

    private mixed  $officialUserRepo;
    private string $code;

    /**
     * @throws InvalidArgumentException
     */
    public function __construct()
    {
        $config                 = [
            'app_id'  => 'wx9aae573ec9c2a3cf',
            'secret'  => '6055cd8ec476a8510b51a933a85d9987',
            'token'   => 'Kepter',
            'aes_key' => 'I5tSSdTbCynWGhIxii2CkRTnCP1jxXuzhTa1UJWZUAP', // 明文模式请勿填写 EncodingAESKey

            /**
             * 接口请求相关配置，超时时间等，具体可用参数请参考：
             * https://github.com/symfony/symfony/blob/5.3/src/Symfony/Contracts/HttpClient/HttpClientInterface.php
             */
            'http'    => [
                'timeout' => 5.0,
                // 'base_uri' => 'https://api.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用，根据不同的模块配置不同的 uri

                'retry' => true, // 使用默认重试配置
                //  'retry' => [
                //      // 仅以下状态码重试
                //      'http_codes' => [429, 500]
                //       // 最大重试次数
                //      'max_retries' => 3,
                //      // 请求间隔 (毫秒)
                //      'delay' => 1000,
                //      // 如果设置，每次重试的等待时间都会增加这个系数
                //      // (例如. 首次:1000ms; 第二次: 3 * 1000ms; etc.)
                //      'multiplier' => 3
                //  ],
            ],
        ];
        $this->official         = new Application($config);
        $this->utils            = $this->official->getUtils();
        $this->officialUserRepo = app(WechatOfficialUserRepositoryInterface::class);
    }

    function redirect_url(string $url)
    {
        return $this->official->getOAuth()->redirect($url);
    }

    public function access_token(): string
    {
        return $this->official->getAccessToken()->getToken();
    }

    public function application()
    {
        return $this->official;
    }

    public function setCode(string $code): self
    {
        $this->code = $code;
        return $this;
    }

    /**
     * @throws InvalidArgumentException
     */
    function login(): WechatLoginResp
    {
        $code        = $this->code;
        $wechat_user = $this->official->getOAuth()->userFromCode($code);
        $attr        = $wechat_user->getAttributes();
        $union_id    = $attr['raw']['unionid'];
        $userRepo    = app(UserRepositoryInterface::class);
        $user        = $userRepo->getUserByUnionIdOpenIdType($union_id, $wechat_user->getId(), User::CLIENT_TYPE_WECHAT_OFFICIAL);

        $addUserData = [
            'openid'      => $wechat_user->getId(),
            'unionid'     => $union_id,
            'appid'       => $this->official->getAccount()->getAppId(),
            'client_type' => User::CLIENT_TYPE_WECHAT_OFFICIAL,
        ];
        if (!$user) {
            $user = $userRepo->addUser($addUserData);
        } else {
            $official_user = $userRepo->getOfficialUserByOpenId($user, $addUserData['openid']);
            if (!$official_user) {
                $userRepo->addOfficialUser($user, $addUserData);
            }

        }
        return new WechatLoginResp($user);
    }

    public function subscribe(string $openid): bool
    {
        if ($user = $this->getOfficialUser($openid)) {
            $this->officialUserRepo->updateData($user, ['subscribe' => 1]);
        }
        return true;
    }

    public function getOfficialUser(string $openid): ?WechatOfficialUser
    {
        return $this->officialUserRepo->findByOpenId($openid);
    }

    public function unsubscribe(string $openid): bool
    {
        if ($user = $this->getOfficialUser($openid)) {
            $this->officialUserRepo->updateData($user, ['subscribe' => 0]);
        }
        return true;
    }
}